package rs.networx.dao;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.persistence.Query;

import rs.networx.dao.PersonDao;

import rs.networx.entity.Activation;
import rs.networx.entity.Person;
import rs.networx.entity.Post;
import rs.networx.entity.FriendRequest;
/*import rs.networx.enumeration.FriendReqCategory;
 import rs.networx.enumeration.NottificationCategory;*/
import rs.networx.entity.Nottification;

@Stateless
@Local(PersonDao.class)
public class PersonDaoBean extends GenericDaoBean<Person, Integer> implements
		PersonDao {

	@EJB
	private PersonDao personDao;
	@EJB
	FriendRequestDao friendRequestDao;
	@EJB
	NottificationDao nottificationDao;

	@SuppressWarnings("unchecked")
	@Override
	public Person login(String email, String password) {

		System.out.println("Logujemo korisnika: " + email + "/n");
		System.out.println("sifra:" + password);

		Query q = em
				.createQuery("SELECT p FROM Person p WHERE p.email=:email AND p.password=:password");
		q.setParameter("email", email);
		q.setParameter("password", password);
		List<Person> persons = q.getResultList();

		if (persons.size() == 0) {
			return null;
		}

		Person p = persons.get(0);
		return p;

	}

	@Override
	public boolean activate(Integer personID, Long activationCode) {
		System.out.println("Activated: " + personID + ", with code: "
				+ activationCode);

		Query q = em
				.createQuery("SELECT a FROM Activation a WHERE a.activator=:activator "
						+ "AND a.activationCode=:activationCode");

		Person person = findById(personID);
		if (person == null) {
			System.out.println("ERROR: Trazeni person ne postoji!");
			return false;
		}

		q.setParameter("activationCode", activationCode);
		q.setParameter("activator", person);
		Activation a = (Activation) q.getSingleResult();

		if (a == null) {
			System.out.println("ERROR: Trazena aktivacija ne postoji!");

			return false;
		}

		person.setActivated(true);
		return true;

	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Person> search(String searchText) {
		Query q = em.createQuery("SELECT p FROM Person p "
				+ "WHERE p.firstName LIKE :searchText "
				+ "OR p.lastName LIKE :searchText AND activated = 1");
		q.setParameter("searchText", searchText);

		List<Person> resultList = q.getResultList();
		return resultList;

	}

	@Override
	public List<Post> getFirstTenOwnedPosts(Integer personID) {
		Person person = findById(personID);
		System.out.println("Getting posts...");

		Query q = em
				.createQuery("SELECT p FROM Post p WHERE p.owner=:owner ORDER BY p.date DESC");
		q.setParameter("owner", person);

		@SuppressWarnings("unchecked")
		List<Post> posts = q.getResultList();

		// getting first 10 or as much as list has
		if (posts.size() > 10) {
			posts = posts.subList(0, 10);
		} else {
			posts = posts.subList(0, posts.size());
		}

		System.out.println("Loaded: " + posts.size() + " posts");
		return posts;

	}

	@Override
	public boolean areFriends(Integer personID, Integer friendID) {

		System.out.println("Checking friend status:   ...  ");
		Set<Person> friends = findById(personID).getFriends();

		if (personID == friendID) {
			return false;
		}
		return friends.contains(findById(friendID));
	}

	@Override
	public Set<Person> getFriends(Integer personID) {

		System.out.println("Getting friends...");
		// EAGER fetching friends
		Query q = em
				.createQuery("SELECT DISTINCT p FROM Person p LEFT JOIN FETCH p.friends  WHERE p.id=:id");
		q.setParameter("id", personID);
		Person person = (Person) q.getSingleResult();

		// getting friends
		Set<Person> friends = person.getFriends();

		System.out.println("Loaded: " + friends.size() + " friends");
		return friends;
	}

	@Override
	public boolean addFriendRequest(Integer personID, Integer friendID) {

		System.out.println("Adding friend request...");

		// checking for errors
		Person person = findById(personID);
		System.out.println("My person: " + personID);
		Person friend = findById(friendID);
		System.out.println("Target person: " + friendID);
		// if person for friend doens't exists, return false
		if (person == null || friend == null) {
			System.out.println("Error in first if");
			return false;
		}
		System.out.println("Tu sam... 1");
		// adding new friend request with Pending status
		FriendRequest friendRequest = new FriendRequest();
		System.out.println("Friend request: " + friendRequest);

		friendRequest.setDate(Calendar.getInstance().getTime());
		System.out.println("Friend request: " + friendRequest);

		friendRequest.setRequestFrom(person);
		System.out.println("Friend request: " + friendRequest);

		friendRequest.setRequestTo(friend);
		System.out.println("Friend request: " + friendRequest);

		friendRequest.setStatus(1); // jer ne radi enumeracija zato sto je ovo
									// java :(
		System.out.println("Friend request: " + friendRequest);

		friendRequestDao.persist(friendRequest);

		// adding nottification to target person
		System.out.println("Tu sam... 2");
		Nottification nottification = new Nottification();
		nottification.setOwner(friend);
		nottification.setTargetID(friendRequest.getId());
		nottification.setType(1);
		nottification.setViewed(false);
		nottification.setLink("<a href=\"personsReg?confirmFriendReq=true"
				+ "&friendRequestID=" + friendRequest.getId()
				+ "&nottificationID=" + nottification.getId()
				+ "\">New friend request from: " + person.getFirstName() + " "
				+ person.getLastName() + "</a>");

		nottificationDao.persist(nottification);

		return true;

	}

	@Override
	public boolean addToFriends(Integer friendRequestID) {

		System.out.println("Adding friends...");

		FriendRequest friendRequest = friendRequestDao
				.findById(friendRequestID);

		// checking for errors
		Person person = friendRequest.getRequestFrom();
		Person friend = friendRequest.getRequestTo();
		// if person for friend doens't exists, return false
		if (person == null || friend == null) {
			return false;
		}

		Set<Person> friends = person.getFriends();
		// if person exists already in friends, return false
		if (friends.contains(friend)) {
			return false;
		}
		// adding friendship in both persons
		friends.add(friend);
		friend.getFriends().add(person);
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean checkUsernameExistance(String usernameToCheck) {

		Query q = em.createQuery("SELECT p FROM Person p WHERE p.email=:email");
		q.setParameter("email", usernameToCheck);
		List<Person> results = q.getResultList();
		if (results.size() == 0) {
			return false;
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<String> getAllUsernames() {

		Query q = em.createQuery("SELECT email FROM Person");
		List<String> results = q.getResultList();

		// if person doesn't exist
		if (results.size() == 0) {
			return null;
		}
		return results;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Person logout(String username, String password) {
		System.out.println("** LOGOUTUJEMO: " + username + ", " + password);

		Query q = em
				.createQuery("SELECT p FROM Person p WHERE p.email=:email AND p.password=:password");

		q.setParameter("email", username);
		q.setParameter("password", password);

		List<Person> results = q.getResultList();

		// if person doesn't exist
		if (results.size() == 0) {
			return null;
		}

		// get first, and there is only one
		Person p = results.get(0);
		return p;
	}

	@Override
	public boolean checkIfMutual(Integer intLoggedUserID,
			Integer intSelectedPersonID, Integer personID) {
		System.out.println("Loaded checkIfMutual...");

		boolean result = false;
		ArrayList<Person> mutualFriends = getAllMutualFriends(intLoggedUserID,
				intSelectedPersonID);

		for (int i = 0; i < mutualFriends.size(); i++) {
			if (mutualFriends.get(i).getId().equals(personID)) {
				result = true;
				break;
			}
		}
		System.out.println("mutual: " + result + " " + personID);
		return result;
	}

	@Override
	public ArrayList<Person> getAllMutualFriends(Integer intLoggedUserID,
			Integer intSelectedPersonID) {
		System.out.println("Loaded getAllMutualFriends...");

		ArrayList<Person> result = new ArrayList<Person>();

		Set<Person> loggedUsersFriendsSet;
		Set<Person> selectedPersonsFriendsSet;

		ArrayList<Person> loggedUsersFriendsList;
		ArrayList<Person> selectedPersonsFriendsList;

		loggedUsersFriendsSet = personDao.getFriends(intLoggedUserID);
		selectedPersonsFriendsSet = personDao.getFriends(intSelectedPersonID);

		if (loggedUsersFriendsSet != null && loggedUsersFriendsSet.size() > 0) {
			if (selectedPersonsFriendsSet != null
					&& selectedPersonsFriendsSet.size() > 0) {

				// pretvaramo loggedUsersFriendsSet u listu
				// loggedUsersFriendsList...
				loggedUsersFriendsList = new ArrayList<Person>();

				Iterator<Person> iter = loggedUsersFriendsSet.iterator();
				while (iter.hasNext()) {
					loggedUsersFriendsList.add((Person) iter.next());
				}
				System.out.println("loggedUsersFriendsList: "
						+ loggedUsersFriendsList.size());

				// pretvaramo selectedPersonsFriendsSet u listu
				// selectedPersonsFriendsList...
				selectedPersonsFriendsList = new ArrayList<Person>();

				Iterator<Person> iter2 = selectedPersonsFriendsSet.iterator();
				while (iter2.hasNext()) {
					selectedPersonsFriendsList.add((Person) iter2.next());
				}
				System.out.println("selectedPersonsFriendsList: "
						+ selectedPersonsFriendsList.size());

				// sada trazimo mutual friends...
				for (int i = 0; i < loggedUsersFriendsList.size(); i++) {
					for (int j = 0; j < selectedPersonsFriendsList.size(); j++) {
						if (loggedUsersFriendsList.get(i).getId()
								.equals(intLoggedUserID)
								|| loggedUsersFriendsList.get(i).getId()
										.equals(intSelectedPersonID)) {
							continue;
						}
						if (loggedUsersFriendsList
								.get(i)
								.getId()
								.equals(selectedPersonsFriendsList.get(j)
										.getId())) {
							result.add(loggedUsersFriendsList.get(i));
							break;
						}
					}
				}

				System.out.println("mutual friends count: " + result.size());
				for (int i = 0; i < result.size(); i++) {
					System.out.println(result.get(i));
				}
			} else if (selectedPersonsFriendsSet == null
					|| selectedPersonsFriendsSet.size() == 0) {
				// znaci da nema prijatelja...
				System.out.println("selectedPersonsFriendsSet: "
						+ selectedPersonsFriendsSet.size());
			}
		} else if (loggedUsersFriendsSet == null
				|| loggedUsersFriendsSet.size() == 0) {
			// znaci da nema prijatelja...
			System.out.println("loggedUsersFriendsSet: "
					+ loggedUsersFriendsSet.size());
		}
		return result;
	}

	@Override
	public boolean removeFromFriends(Integer intLoggedUserID,
			Integer intPersonToDeleteID) {
		System.out.println("Loaded addToFriends...");

		boolean result = false;
		Person loggedUser = null;
		Person personToDelete = null;

		if (intLoggedUserID != null && intPersonToDeleteID != null) {
			System.out.println("intLoggedUserID: " + intLoggedUserID);
			System.out.println("intPersonToDeleteID: " + intPersonToDeleteID);

			loggedUser = personDao.findById(intLoggedUserID);
			personToDelete = personDao.findById(intPersonToDeleteID);

			if (loggedUser != null && personToDelete != null) {
				System.out.println("loggedUser: " + loggedUser);
				System.out.println("personToDelete: " + personToDelete);

				Set<Person> loggedUsersFriends = loggedUser.getFriends();
				Set<Person> personToDeleteFriends = personToDelete.getFriends();

				if (loggedUsersFriends.contains(personToDelete)
						&& personToDeleteFriends.contains(loggedUser)) {
					loggedUsersFriends.remove(personToDelete);
					personToDeleteFriends.remove(loggedUser);
					result = true;
				}
			}
		}
		return result;
	}
}
